//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2006-2007
//
// NaviTel Tracks.bin file parser.
//

# include "StdAfx.h"
# include "Map.h"
# include "Load.h"
# include "Log.h"
# include "Status.h"
# include "Wrappers.h"
# include "Globals.h"

const size_t c_cMaxPoints = 10000;

struct track_point_t {
	long lX;
	long lY        : 31,
	     bNewTrack : 1;
};

struct track_log_t {
	DWORD dwEnd;
	DWORD dwOverflow;
	track_point_t points [c_cMaxPoints];
};

class CTracksBinLoader : public CMapLoader {
  public:
	// Override.
	virtual bool IsValid (const char * _pData, size_t _cFileSize) const;
	virtual LoadStatus_t Load (const char * _pData, size_t _cFileSize, const char * _strFileName, map_t * _pMap);

  private:
	map_t * m_pMap;
	const char * m_pStart, * m_pEnd;

	file_refs_t m_file_refs;

	void _CompleteTrack (rgn_t & _track, points_t & _points);
};

DECLARE_WPTRK_LOADER (CTracksBinLoader, "navitel-tracks-bin", "bin", "Navitel tracks buffer (*.bin)", ftiTracks);

bool CTracksBinLoader::IsValid (const char * _pData, size_t _cFileSize) const {
	return _cFileSize == sizeof (track_log_t);
}

void CTracksBinLoader::_CompleteTrack (rgn_t & _track, points_t & _points) {
	const size_t cPoints = _points.size ();

	track_info_t * const pTrackExtra = _track.pExtra->wtr.CreateTrack ();
	if (_track.elements.empty ())
		return;
	trackpoints_t & TrackPoints = _track.elements [0].pExtra->TrackPoints;

	TrackPoints.resize (cPoints);
	for (size_t c = 0; c < cPoints; ++ c) {
		trackpoint_info_t & tpi = TrackPoints [c];
		tpi.wFlags = 0;
	}
}

LoadStatus_t CTracksBinLoader::Load (const char * _pData, size_t _cFileSize, const char * _strMapFileName, map_t * _pMap) {
	m_pMap   = _pMap;
	m_pStart = _pData;
	m_pEnd   = _pData + _cFileSize;

	m_file_refs.clear ();
	m_file_refs.push_back (file_ref_t ());
	m_file_refs.back ().strFileName = _strMapFileName;
	m_file_refs.back ().bAttachment = true;

	SetProgressStatus (0);

	m_pMap->cHeaderLen = 0;

	const track_log_t * const pTrack = reinterpret_cast<const track_log_t *> (_pData);
	const size_t cBegin  = pTrack->dwOverflow ? pTrack->dwEnd : 0;
	const size_t cPoints = pTrack->dwOverflow ? c_cMaxPoints : pTrack->dwEnd;

	rgn_t * pRgnTrack = NULL;
	points_t * pPoints = NULL;
	for (size_t c = 0; c < cPoints; ++ c) {
		const track_point_t & tp = pTrack->points [cBegin + c < c_cMaxPoints ? cBegin + c : cBegin + c - c_cMaxPoints];

		if (tp.bNewTrack || pPoints == NULL) {
			rgn_t & rgn = m_pMap->CreateRgn (rkPolyline);
			rgn.SetTrackType ();

			rgn.pFileRef  = & m_file_refs.back ();
			rgn.cBeginPos = 0;
			rgn.cEndPos   = 0;
			rgn.cFileLine = -1;

			rgn.elements.push_back (rgn_element_t ());
			rgn_element_t & element = rgn.elements.back ();
			element.cFileOffset = 0;
			element.cLevel      = 0;

			pPoints = & element.points;
			pPoints->reserve (c_cMaxPoints);

			if (pRgnTrack)
				_CompleteTrack (* pRgnTrack, * pPoints);
			pRgnTrack = & rgn;
		}

		const point_t point (tp.lX*180.f/(1UL << 31), tp.lY*180.f/(1UL << 31));
		assert (pPoints);
		pPoints->push_back (point);
	}

	if (pRgnTrack)
		_CompleteTrack (* pRgnTrack, * pPoints);

	SetProgressStatus (50);

	m_pMap->file_refs.swap (m_file_refs);

	// Suppress warning about empty Zoom etc.
	m_pMap->bNoHeader = true;

	return lsOK;
}
